/*
 * Part of knowledge engineering (ke) course work, 2010/11
 */
package se.bth.ke.firstfriend.depend;

import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import se.bth.ke.firstfriend.model.Article;
import se.bth.ke.firstfriend.model.ArticleDependency;

/**
 * Manages dependencies of articles between each other
 * @author nico.rehwaldt
 */
@Component
public class ArticleDependencyManager {

    @PersistenceContext
    private EntityManager em;

    /**
     * Adds the dependencies to the given article
     * 
     * @param task
     * @param dependencies
     */
    @Transactional
    public void addDependencies(Article task, List<Article> dependencies) {
        Query query = em.createQuery("SELECT d FROM ArticleDependency d WHERE d.task = :task AND d.dependsOn = :dependsOn")
                        .setParameter("task", task);

        for (Article a: dependencies) {
            try {
                query.setParameter("dependsOn", a)
                     .getSingleResult();
            } catch (NoResultException e) {
                // Dependency was not found... create it!
                ArticleDependency dependency = new ArticleDependency(task, a);
                em.persist(dependency);
                em.flush();
            }
        }
    }

    /**
     * Get suggested dependencies for a given task excluding
     * task in the passed exclusions list
     * 
     * @param task
     * @param exclusions
     * @return
     */
    @Transactional
    public List<Article> getDependencySuggestions(Article task, List<Article> exclusions) {
        List<Article> dependencies = getDependencies(task);
        List<Article> result = new ArrayList();

        for (Article dependency: dependencies) {
            if (!exclusions.contains(dependency)) {
                result.add(dependency);
            }
        }

        return result;
    }

    /**
     * Return the dependencies of a given task
     * @param task
     * @return
     */
    @Transactional
    public List<Article> getDependencies(Article task) {
        List<Article> dependencies = em.createQuery("SELECT d.dependsOn FROM ArticleDependency d WHERE d.task = :task")
                                       .setParameter("task", task)
                                       .getResultList();
        
        return dependencies;
    }

    /**
     * Return the tasks which directly depend on a given one
     * 
     * @param task 
     * @return the list of dependent articles
     */
    @Transactional
    public List<Article> getDependentArticles(Article task) {
        List<Article> dependencies = em.createQuery("SELECT d.task FROM ArticleDependency d WHERE d.dependsOn = :task")
                                       .setParameter("task", task)
                                       .getResultList();
                                       
        return dependencies;
    }
}
